package com.uduemc.biso.node.web.component;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.extities.pojo.NginxServerConf;
import com.uduemc.biso.core.utils.TemplateUtil;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.SitePathUtil;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class NginxServer {

	@Autowired
	private GlobalProperties globalProperties;

	@Autowired
	private VelocityEngine velocityEngine;

	@Autowired
	private NginxOperate nginxOperate;

	public String makeIncludePath(long hostId) {
		String basePath = globalProperties.getNginx().getVhosts();
		String path = TemplateUtil.makeLocalDirectory(basePath, hostId);
		return path;
	}

	public String makeIncludeFileName(String serverName) {
		return serverName + ".conf";
	}

	public String makeIncludeFile(long hostId, String serverName) {
		String makeIncludePath = makeIncludePath(hostId);
		return makeIncludePath + File.separator + makeIncludeFileName(serverName);
	}

	public String makeAccessLog(String domain, String randomCode) throws IOException {
		String basePath = SitePathUtil.getUserNginxlogPathByCode(globalProperties.getSite().getBasePath(), randomCode);
		String path = basePath + File.separator + "access." + StrUtil.replace(domain, ".", "_") + ".nginxlog";
		File file = new File(path);
		if (!file.isFile()) {
			FileUtils.writeStringToFile(file,
					"start " + domain + " log at " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n", "UTF-8");
		}
		return path;
	}

	public String makeErrorLog(String domain, String randomCode) throws IOException {
		String basePath = SitePathUtil.getUserNginxlogPathByCode(globalProperties.getSite().getBasePath(), randomCode);
		String path = basePath + File.separator + "error." + StrUtil.replace(domain, ".", "_") + ".nginxlog";
		File file = new File(path);
		if (!file.isFile()) {
			FileUtils.writeStringToFile(file,
					"start nginx error log at " + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) + "\n", "UTF-8");
		}
		return path;
	}

	public String makeNginxHistoryLogDir(String domain, String randomCode) throws IOException {
		String basePath = SitePathUtil.getUserNginxHistorylogPathByCode(globalProperties.getSite().getBasePath(), randomCode);
		String dir = basePath + File.separator + StrUtil.replace(domain, ".", "_");
		if (FileUtil.isFile(dir)) {
			FileUtil.del(dir);
		}
		if (!FileUtil.isDirectory(dir)) {
			FileUtil.mkdir(dir);
		}
		return dir;
	}

	public String makeText(NginxServerConf ser) {
		Map<String, Object> mapData = new HashMap<String, Object>();
		mapData.put("server", ser);
		VelocityContext ctx = new VelocityContext(mapData);
		Template t = velocityEngine.getTemplate("templates/velocity/nginx/server.vm");
		StringWriter sw = new StringWriter();
		t.merge(ctx, sw);
		String server = sw.toString();
		log.info(server);
		return server;
	}

	public boolean make(Host host, NginxServerConf ser) throws IOException {
		ser.setAccessLog(makeAccessLog(ser.getServerName(), host.getRandomCode())).setErrorLog(makeErrorLog(ser.getServerName(), host.getRandomCode()));
		String makeText = makeText(ser);
		String makeIncludeFile = makeIncludeFile(host.getId(), ser.getServerName());
		File file = new File(makeIncludeFile);
		if (file.isFile()) {
			file.delete();
		}
		log.info(file.toString());
		FileUtils.writeStringToFile(file, makeText, "UTF-8");
		if (!file.isFile()) {
			return false;
		}
		return FileUtils.sizeOf(file) > 0;
	}

	public boolean bindDomain(Host host, NginxServerConf ser) throws IOException {
		return bindDomain(host, ser, true);
	}

	public boolean bindDomain(Host host, NginxServerConf ser, boolean reload) throws IOException {
		ser.setAccessLog(makeAccessLog(ser.getServerName(), host.getRandomCode())).setErrorLog(makeErrorLog(ser.getServerName(), host.getRandomCode()));
		String makeText = makeText(ser);
		String makeIncludeFile = makeIncludeFile(host.getId(), ser.getServerName());
		File file = new File(makeIncludeFile);
		if (file.isFile()) {
			file.delete();
		}
		log.info(file.toString());
		FileUtils.writeStringToFile(file, makeText, "UTF-8");
		if (!file.isFile()) {
			return false;
		}

		if (FileUtils.sizeOf(file) <= 0) {
			return false;
		}

		// 对生成的 nginx server 配置文件进行校验
		boolean boolTest = nginxOperate.boolTest();
		if (!boolTest) {
			FileUtil.del(file);
			log.error("测试 Nginx 失败，报错内容：\n" + nginxOperate.test());
			return false;
		}

		// 如果 reload 为 false 则不需要重启 nginx
		if (reload == false) {
			return true;
		}

		boolean boolReload = nginxOperate.boolReload();
		if (!boolReload) {
			log.error("重启 Nginx 失败，报错内容：" + nginxOperate.reload());
			return false;
		}
		return true;
	}

	public boolean unbindDomain(Host host, String domain) throws IOException {
		String makeIncludeFile = makeIncludeFile(host.getId(), domain);
		if (FileUtil.isFile(makeIncludeFile)) {
			FileUtil.del(makeIncludeFile);
		}

		String makeAccessLog = makeAccessLog(domain, host.getRandomCode());
		if (FileUtil.isFile(makeAccessLog)) {
			FileUtil.del(makeAccessLog);
		}

		String makeErrorLog = makeErrorLog(domain, host.getRandomCode());
		if (FileUtil.isFile(makeErrorLog)) {
			FileUtil.del(makeErrorLog);
		}

		String makeNginxHistoryLogDir = makeNginxHistoryLogDir(domain, host.getRandomCode());
		if (FileUtil.isDirectory(makeNginxHistoryLogDir)) {
			FileUtil.del(makeNginxHistoryLogDir);
		}

		return true;
	}
}
